package backed.service.impl;

import backed.entity.EcoQARecord;
import backed.entity.EcoActionPlan;
import backed.repository.AiRepository;
import backed.repository.EcoActionPlanRepository;
import backed.service.AiService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * AI服务实现类
 * 功能：调用Coze AI接口，处理环保问答和方案生成
 */
@Service
public class AiServiceImpl implements AiService {

    // 数据库操作对象（用于保存问答记录）
    @Autowired
    private AiRepository repository;
    
    // 数据库操作对象（用于保存环保方案）
    @Autowired
    private EcoActionPlanRepository planRepository;

    // HTTP客户端（用于调用Coze API）
    private final WebClient webClient;
    
    // 机器人ID常量
    private static final String QA_BOT_ID = "7577391588163895348";  // 环保知识问答机器人ID
    private static final String PLAN_BOT_ID = "7576995538957287466";  // 生成环保方案机器人ID

    /**
     * 构造函数：初始化时创建WebClient，配置Coze API的地址和认证信息
     */
    public AiServiceImpl() {
        this.webClient = WebClient.builder()
                .baseUrl("https://api.coze.cn/v3")  // Coze API的基础地址
                .defaultHeader("Authorization", "Bearer pat_9irnbeU2KfAG1HaCyBnOQYyhdRCt7IHsTncywyFRY82fQ8GbXlpBIYeGaatUQ6EK")  // API密钥
                .build();
    }

    /**
     * 初始化方法：服务启动时执行
     */
    @PostConstruct
    public void init() {
        System.out.println("√ AI服务模块初始化完成...");
    }

    /**
     * 方法1：回答环保问题
     * @param userId 用户ID（用于保存记录）
     * @param question 用户的问题
     * @return 包含答案的响应结果
     */
    @Override
    public Map<String, Object> answerQuestion(Long userId, String question) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 步骤1：调用Coze AI获取答案（使用问答机器人）
            String answer = callCozeStream(question, userId, QA_BOT_ID);
            
            // 步骤1.5：清理答案中的换行符等特殊符号
            answer = cleanAnswerText(answer);
            
            // 步骤2：构建成功响应
            result.put("success", true);
            result.put("data", Map.of("answer", answer));
            
        } catch (Exception e) {
            // 如果出错，返回错误信息
            result.put("success", false);
            result.put("message", "AI服务调用失败：" + e.getMessage());
            result.put("data", Map.of("answer", ""));
        }
        return result;
    }

    /**
     * 方法2：生成个性化环保方案
     * @param userId 用户ID（用于保存记录）
     * @param region 地区（可以为null）
     * @param familySize 家庭人数（可以为null）
     * @param transportMode 出行方式（可以为null）
     * @return 包含方案内容的响应结果
     */
    @Override
    public Map<String, Object> generatePlan(Long userId, String region, Integer familySize, String transportMode) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 步骤1：构建context（AI需要的上下文信息）
            String context = buildContext(region, familySize, transportMode);
            
            // 步骤2：调用Coze AI生成方案（使用方案生成机器人）
            String planContent = callCozeStream(context, userId, PLAN_BOT_ID);
            
            // 步骤2.5：清理方案内容中的换行符等特殊符号
            planContent = cleanAnswerText(planContent);
            
            // 步骤3：保存方案到数据库
            savePlanToDatabase(userId, region, familySize, transportMode, planContent);
            
            // 步骤4：构建成功响应
            result.put("success", true);
            result.put("data", Map.of("planContent", planContent));
            
        } catch (Exception e) {
            // 如果出错，返回错误信息
            result.put("success", false);
            result.put("message", "AI服务调用失败：" + e.getMessage());
            result.put("data", Map.of("planContent", ""));
        }
        return result;
    }
    
    /**
     * 构建context字符串（把用户信息组合成AI能理解的格式）
     */
    private String buildContext(String region, Integer familySize, String transportMode) {
        // 如果所有参数都有，组合成完整信息
        if (region != null && familySize != null && transportMode != null) {
            return String.format("地区：%s，家庭人数：%d，出行方式：%s", region, familySize, transportMode);
        }
        // 如果只有region，就用region
        if (region != null) {
            return region;
        }
        // 都没有就返回默认值
        return "未指定";
    }

    /**
     * 核心方法：调用Coze AI接口
     * @param question 问题或上下文信息
     * @param userId 用户ID（如果为0则不保存记录）
     * @param botId 机器人ID
     * @return AI返回的答案
     */
    private String callCozeStream(String question, Long userId, String botId) {
        try {
            // 步骤1：构建请求体（JSON格式）
            String requestBody = buildRequestBody(userId, question, botId);

            // 步骤2：发送HTTP POST请求到Coze API
            Flux<String> stream = webClient.post()
                    .uri("/chat")  // API路径
                    .header("Content-Type", "application/json")  // 告诉服务器发送的是JSON
                    .header("Accept", "text/event-stream")  // 告诉服务器我们接受流式数据
                    .bodyValue(requestBody)  // 请求体
                    .retrieve()  // 执行请求
                    .onStatus(status -> status.is4xxClientError() || status.is5xxServerError(), 
                        response -> {
                            // 如果返回错误状态码，抛出异常
                            return response.bodyToMono(String.class)
                                .then(Mono.error(new RuntimeException("API 请求失败: " + response.statusCode())));
                        })
                    .bodyToFlux(String.class);  // 接收流式响应

            // 步骤3：处理流式响应，提取AI的答案
            return processStreamResponse(stream, userId, question);
            
        } catch (Exception e) {
            // 如果出错，返回错误信息
            return "请求处理失败: " + e.getMessage();
        }
    }

    /**
     * 构建请求体（JSON格式）
     * Coze API需要特定的JSON格式，这个方法负责构建
     * @param userId 用户ID
     * @param question 问题或上下文信息
     * @param botId 机器人ID
     */
    private String buildRequestBody(Long userId, String question, String botId) {
        try {
            // 方式1：使用ObjectMapper构建JSON（推荐，更安全）
            ObjectMapper mapper = new ObjectMapper();
            Map<String, Object> body = new HashMap<>();
            
            // 设置机器人ID
            body.put("bot_id", botId);
            // 设置用户ID（转成字符串）
            body.put("user_id", String.valueOf(userId));
            // 启用流式响应
            body.put("stream", true);
            
            // 构建消息数组（AI需要知道用户说了什么）
            List<Map<String, String>> messages = new ArrayList<>();
            Map<String, String> userMessage = new HashMap<>();
            userMessage.put("role", "user");  // 角色：用户
            userMessage.put("type", "question");  // 类型：问题
            userMessage.put("content_type", "text");  // 内容类型：文本
            userMessage.put("content", question);  // 内容：用户的问题
            messages.add(userMessage);
            body.put("additional_messages", messages);
            
            // 把Map转换成JSON字符串
            return mapper.writeValueAsString(body);
            
        } catch (Exception e) {
            // 方式2：如果JSON构建失败，使用字符串拼接（备用方案）
            // 需要转义特殊字符，避免JSON格式错误
            String escapedQuestion = question.replace("\\", "\\\\")
                                             .replace("\"", "\\\"")
                                             .replace("\n", "\\n")
                                             .replace("\r", "\\r");
            return String.format(
                "{\"bot_id\":\"%s\",\"user_id\":\"%s\",\"stream\":true,\"additional_messages\":[{\"role\":\"user\",\"type\":\"question\",\"content_type\":\"text\",\"content\":\"%s\"}]}",
                botId,
                String.valueOf(userId),
                escapedQuestion
            );
        }
    }

    /**
     * 处理流式响应
     * Coze API返回的是流式数据（像打字机一样一段一段返回），需要把所有片段拼接起来
     */
    private String processStreamResponse(Flux<String> stream, Long userId, String question) {
        // 用于存储完整的答案
        StringBuilder fullAnswer = new StringBuilder();
        // 用于去重（避免重复内容）
        Set<String> processed = new HashSet<>();
        // JSON解析器
        ObjectMapper mapper = new ObjectMapper();
        // 标记是否有错误（使用数组是因为Lambda表达式需要final变量）
        final boolean[] hasError = {false};
        final String[] errorMessage = {null};

        try {
            // 处理每一段流式数据
            stream
                .doOnNext(dataChunk -> {
                    try {
                        // 步骤1：清理数据（去掉"data: "前缀，处理空行）
                        String jsonData = cleanStreamData(dataChunk);
                        if (jsonData == null) return;  // 跳过无效数据

                        // 步骤2：解析JSON
                        JsonNode node = mapper.readTree(jsonData);

                        // 步骤3：检查是否有错误
                        if (checkForError(node)) {
                            hasError[0] = true;
                            errorMessage[0] = extractErrorMessage(node);
                            return;
                        }

                        // 步骤4：提取答案内容（只处理answer和final_answer类型）
                        String content = extractAnswerContent(node);
                        if (content != null && !content.isEmpty()) {
                            // 去重后添加到完整答案中
                            if (!processed.contains(content)) {
                                processed.add(content);
                                fullAnswer.append(content);
                            }
                        }

                    } catch (Exception e) {
                        // 如果某一段数据解析失败，继续处理下一段（不中断）
                    }
                })
                .doOnError(error -> {
                    // 如果整个流出现错误
                    hasError[0] = true;
                    errorMessage[0] = "流式请求错误: " + error.getMessage();
                })
                .blockLast(Duration.ofMinutes(5));  // 等待流式响应完成（最多等5分钟）

            // 步骤5：根据处理结果返回
            if (hasError[0]) {
                // 有错误，返回错误信息
                String finalAnswer = errorMessage[0] != null ? errorMessage[0] : "请求处理失败";
                saveUserRecord(userId, question, finalAnswer);
                return finalAnswer;
            } else if (fullAnswer.length() > 0) {
                // 成功，返回完整答案
                String answer = fullAnswer.toString();
                saveUserRecord(userId, question, answer);
                return answer;
            } else {
                // 没有收到任何内容
                String noContentMsg = "未收到有效响应内容";
                saveUserRecord(userId, question, noContentMsg);
                return noContentMsg;
            }
            
        } catch (Exception e) {
            // 如果整个处理过程出错
            String errorMsg = "处理响应时发生错误: " + e.getMessage();
            saveUserRecord(userId, question, errorMsg);
            return errorMsg;
        }
    }
    
    /**
     * 清理流式数据（去掉前缀，跳过空行）
     */
    private String cleanStreamData(String data) {
        String jsonData = data.trim();
        // 去掉SSE格式的"data: "前缀
        if (jsonData.startsWith("data: ")) {
            jsonData = jsonData.substring(6);
        }
        // 跳过空行和注释行
        if (jsonData.isEmpty() || jsonData.startsWith(":")) {
            return null;
        }
        return jsonData;
    }
    
    /**
     * 检查JSON节点中是否有错误
     */
    private boolean checkForError(JsonNode node) {
        // 检查顶层错误
        if (node.has("code")) {
            return true;
        }
        // 检查last_error对象
        if (node.has("last_error")) {
            JsonNode lastError = node.get("last_error");
            if (lastError.has("code")) {
                int errorCode = lastError.get("code").asInt();
                if (errorCode != 0) return true;  // 0表示无错误
            }
        }
        // 检查状态
        if (node.has("status")) {
            String status = node.get("status").asText();
            if ("failed".equals(status) || "cancelled".equals(status)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 提取错误信息
     */
    private String extractErrorMessage(JsonNode node) {
        if (node.has("code")) {
            int code = node.get("code").asInt();
            String msg = node.has("msg") ? node.get("msg").asText() : "未知错误";
            return String.format("API错误 [code: %d, msg: %s]", code, msg);
        }
        if (node.has("last_error")) {
            JsonNode lastError = node.get("last_error");
            if (lastError.has("code")) {
                int errorCode = lastError.get("code").asInt();
                if (errorCode != 0) {
                    String errorMsg = lastError.has("msg") ? lastError.get("msg").asText() : "未知错误";
                    return String.format("任务执行错误 [code: %d, msg: %s]", errorCode, errorMsg);
                }
            }
        }
        if (node.has("status")) {
            String status = node.get("status").asText();
            if ("failed".equals(status) || "cancelled".equals(status)) {
                return "任务状态为: " + status;
            }
        }
        return "未知错误";
    }
    
    /**
     * 提取答案内容（只提取answer和final_answer类型的内容）
     */
    private String extractAnswerContent(JsonNode node) {
        // 跳过状态更新（没有type字段）
        if (!node.has("type")) {
            return null;
        }
        
        // 跳过状态更新（有status字段但不是内容）
        if (node.has("status")) {
            return null;
        }
        
        String type = node.get("type").asText();
        
        // 只处理这两种类型
        if ("answer".equals(type) || "final_answer".equals(type)) {
            if (node.has("content")) {
                return node.get("content").asText();
            }
        }
        
        return null;
    }

    /**
     * 保存问答记录到数据库
     * 注意：如果userId为0，这个方法仍然会保存，但通常userId=0表示匿名用户
     */
    private void saveUserRecord(Long userId, String question, String answer) {
        try {
            // 创建记录对象
            EcoQARecord record = new EcoQARecord();
            record.setUserId(userId);
            record.setQuestion(question);
            record.setAnswer(answer);
            record.setCreateTime(LocalDateTime.now());  // 设置当前时间

            // 保存到数据库
            repository.save(record);
        } catch (Exception e) {
            // 如果保存失败，不抛出异常（不影响主流程）
            // 可以在这里记录日志
        }
    }
    
    /**
     * 保存环保方案到数据库
     * @param userId 用户ID
     * @param region 地区
     * @param familySize 家庭人数
     * @param transportMode 出行方式
     * @param planContent 方案内容
     */
    private void savePlanToDatabase(Long userId, String region, Integer familySize, String transportMode, String planContent) {
        try {
            // 创建方案对象
            EcoActionPlan plan = new EcoActionPlan();
            plan.setUserId(userId);
            plan.setRegion(region);
            plan.setFamilySize(familySize);
            plan.setTransportMode(transportMode);
            plan.setPlanContent(planContent);
            plan.setStatus("active");  // 默认状态为active

            // 保存到数据库
            planRepository.save(plan);
        } catch (Exception e) {
            // 如果保存失败，不抛出异常（不影响主流程）
            // 可以在这里记录日志
            System.err.println("保存环保方案失败: " + e.getMessage());
        }
    }
    
    /**
     * 清理答案文本，去除换行符、回车符等特殊符号
     * 将换行符等替换为空格，保持文本的可读性
     * @param text 原始文本
     * @return 清理后的文本
     */
    private String cleanAnswerText(String text) {
        if (text == null || text.isEmpty()) {
            return text;
        }
        
        // 将换行符、回车符、制表符等替换为空格
        String cleaned = text
            .replace("\n", " ")      // 换行符替换为空格
            .replace("\r", " ")      // 回车符替换为空格
            .replace("\t", " ")      // 制表符替换为空格
            .replace("\f", " ")      // 换页符替换为空格
            .replace("\b", "")       // 退格符直接删除
            .replaceAll("\\s+", " ");  // 将多个连续空格替换为单个空格
        
        // 去除首尾空格
        return cleaned.trim();
    }
}
